home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / NIH Image 1.62b11 / src / Projection.p < prev    next >
Text File  |  1996-03-01  |  44KB  |  989 lines

  1. unit Projection;
  2. {************************************************************************}
  3. {*     Projection.p                                                                                                                                          *}
  4. {*     by Michael Castle (Pascal) and Janice Keller (assembly code)                                                          *}
  5. {*     University of Michigan Mental Health Research Institute (MHRI)                                                     *}
  6. {*     e-mail address: mike.castle@umich.edu                                                                                       *}
  7. {* ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *   * * * * * * * * * }
  8.  
  9. interface
  10.  
  11.     uses
  12.         Types, Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap,
  13.         ToolUtils, Resources, Errors, Palettes, Dialogs, TextUtils,
  14.         Globals, Utilities, File2, File1, Graphics, Camera, Filters, Stacks;
  15.  
  16.  
  17.     procedure DoProjection;
  18.     function ShowProjectDialogBox: boolean;
  19.     procedure Project;
  20.  
  21.  
  22. implementation
  23.  
  24.     const
  25.         bigpowerof2 = 8192;                               {used for integer trigonometric arithmetic}
  26.  
  27.     type
  28.         MHRIRealArray = array[1..MaxPics] of extended;
  29.         RealPoint = record
  30.                 x: extended;
  31.                 y: extended;
  32.             end;     {record}
  33.         IntPtr = ^integer;
  34.         LongPtr = ^LongInt;
  35.  
  36.     var
  37.         SliceInterval: extended;                                 {distance, in pixels, between original slices}
  38.         BoundRect: rect;                                      {boundary rectangle for a rectangular selection}
  39.         cancelled: boolean;
  40.                                                                                                                                                                                                                                         ProjSize: LongInt;
  41.  
  42.  
  43.  
  44. {******************************************************************************}
  45. {*     This procedure frees memory allocated for buffers used in projection calculations.                                       *}
  46. {******************************************************************************}
  47.     procedure DisposeProjectionPtrs (projptr, opaptr, brightcueptr: ptr; zbufptr, countbufptr, cuezbufptr: IntPtr; sumbufptr: LongPtr);
  48.     begin
  49.         if zbufptr <> nil then
  50.             DisposePtr(Ptr(zbufptr));
  51.         if opaptr <> nil then
  52.             DisposePtr(opaptr);
  53.         if sumbufptr <> nil then
  54.             DisposePtr(Ptr(sumbufptr));
  55.         if countbufptr <> nil then
  56.             DisposePtr(Ptr(countbufptr));
  57.         if cuezbufptr <> nil then
  58.             DisposePtr(Ptr(cuezbufptr));
  59.         if brightcueptr <> nil then
  60.             DisposePtr(brightcueptr);
  61.         if projptr <> nil then
  62.             DisposePtr(projptr);
  63.     end;
  64.  
  65.  
  66. {******************************************************************************}
  67. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  68. {*  the x-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  69. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  70. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  71. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  72. {******************************************************************************}
  73.     procedure DoOneProjectionX (nSlices, ycenter, zcenter: integer; projwidth, projheight: LongInt; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  74.         var
  75.             i, j, k,                                                 {loop indices}
  76.             thispixel: integer;                              {the current pixel to be projected}
  77.             offset, offsetinit: longint;                   {precomputed offsets into an image buffer}
  78.             projaddr,                                            {buffer address for final projected image}
  79.             opaaddr,                                              {buffer address for opacity surface projection component}
  80.             brightcueaddr,                                   {buffer address for brightest-point projection with interior depth cues}
  81.             zbufaddr,                                            {z-buffer address for surface projections (nearest-point/opacity)}
  82.             cuezbufaddr,                                       {z-buffer address for brightest-point projection with interior depth cues}
  83.             countbufaddr,                                     {buffer addr for counting pixels in mean-value projection}
  84.             sumbufaddr: longint;                         {buffer addr for summing pixels in mean-value projection}
  85.             z,                                                        {z-coordinate of points in current slice before rotation}
  86.             ynew, znew,                                       {y- and z-coordinates of current point after rotation}
  87.             zmax, zmin,                                       {z-coordinates of first and last slices before rotation}
  88.             zmaxminuszmintimes100: longint;  {precomputed values to save time in loops}
  89.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  90.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  91.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  92.             MeanVal, BrightestPt: boolean;
  93.             ysintheta, ycostheta,                          {values used in rotational calculations before projection}
  94.             zsintheta, zcostheta, ysinthetainit, ycosthetainit: longint;
  95.             p,                                                        {pointer to final projected image buffer}
  96.             op,                                                      {pointer to opacity surface projection buffer}
  97.             bp: ptr;                                              {pointer to brightest-point projection buffer with interior depth cues}
  98.             zp,                                                      {pointer to surface projection (nearest-point/opacity) z-buffer}
  99.             qp,                                                      {pointer to z-buffer for brightest-point projection with interior depth cues}
  100.             cp: IntPtr;                                          {pointer to buffer for counting pixels for mean-value projection}
  101.             sp: LongPtr;                                       {pointer to mean-value summing buffer}
  102.             width: integer;
  103.             theLine: LineType;
  104.     begin
  105.         with BoundRect do begin                    {precompute values to avoid computations in loop}
  106.                 width := right - left;
  107.                 zmax := zcenter + projheight div 2; {find z-coordinates of first and last slices}
  108.                 zmin := zcenter - projheight div 2;
  109.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  110.                 c100minusDepthCueInt := 100 - DepthCueInt;
  111.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  112.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  113.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  114.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  115.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  116.                 MeanVal := ProjectionMethod = MeanValue;
  117.                 BrightestPt := ProjectionMethod = BrightestPoint;
  118.                 projaddr := ord4(projptr);
  119.                 opaaddr := ord4(opaptr);
  120.                 brightcueaddr := ord4(brightcueptr);
  121.                 zbufaddr := ord4(zbufptr);
  122.                 cuezbufaddr := ord4(cuezbufptr);
  123.                 countbufaddr := ord4(countbufptr);
  124.                 sumbufaddr := ord4(sumbufptr);
  125.                 ycosthetainit := (top - ycenter - 1) * costheta;
  126.                 ysinthetainit := (top - ycenter - 1) * sintheta;
  127.                 offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 - 1;
  128.                 for k := 1 to nSlices do begin
  129.                         SelectSlice(k);
  130.                         z := round((k - 1) * SliceInterval) - zcenter;
  131.                         zcostheta := z * costheta;
  132.                         zsintheta := z * sintheta;
  133.                         ycostheta := ycosthetainit;
  134.                         ysintheta := ysinthetainit;
  135.                         for j := top to bottom - 1 do begin               {read each row in the current slice}
  136.                                 ycostheta := ycostheta + costheta;               {rotate about x-axis and find new y,z}
  137.                                 ysintheta := ysintheta + sintheta;               {x-coordinates will not change}
  138.                                 ynew := (ycostheta - zsintheta) div bigpowerof2 + ycenter - top;
  139.                                 znew := (ysintheta + zcostheta) div bigpowerof2 + zcenter;
  140.                                 offset := offsetinit + ynew * projwidth;
  141.                                 GetLine(left, j, width, theLine);
  142.                                 for i := 0 to width - 1 do begin             {read each pixel in current row and project it}
  143.                                         thispixel := theLine[i];
  144.                                         offset := offset + 1;
  145.                                         if (offset >= ProjSize) or (offset < 0) then
  146.                                             offset := 0;
  147.                                         if (thispixel <= TransparencyUpper) and (thispixel >= TransparencyLower) then begin
  148.                                                 if OpacityOrNearestPt then begin
  149.                                                         zp := IntPtr(zbufaddr + offset + offset);
  150.                                                         if (znew < zp^) then begin
  151.                                                                 zp^ := znew;
  152.                                                                 if OpacityAndNotNearestPt then begin
  153.                                                                         op := ptr(opaaddr + offset);
  154.                                                                         if (DepthCueSurflessthan100) then
  155.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  156.                                                                         else
  157.                                                                             op^ := thispixel;
  158.                                                                     end
  159.                                                                 else begin
  160.                                                                         p := ptr(projaddr + offset);
  161.                                                                         if DepthCueSurflessthan100 then
  162.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  163.                                                                         else
  164.                                                                             p^ := thispixel;
  165.                                                                     end;
  166.                                                             end;
  167.                                                     end;     {NearestPoint case}
  168.                                                 if MeanVal then begin
  169.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  170.                                                         sp^ := sp^ + thispixel;
  171.                                                         cp := IntPtr(countbufaddr + offset + offset);
  172.                                                         cp^ := cp^ + 1;
  173.                                                     end     {MeanValue case}
  174.                                                 else if BrightestPt then begin
  175.                                                         if (DepthCueIntlessthan100) then begin
  176.                                                                 p := ptr(projaddr + offset);
  177.                                                                 bp := ptr(brightcueaddr + offset);
  178.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  179.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (znew < qp^)) then begin
  180.                                                                         bp^ := thispixel;                     {use z-buffer to ensure that if depth-cueing is on,  }
  181.                                                                         qp^ := znew;                            {the closer of two equally-bright points is displayed}
  182.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100);
  183.                                                                     end;     {then}
  184.                                                             end
  185.                                                         else begin
  186.                                                                 p := ptr(projaddr + offset);
  187.                                                                 if (thispixel < BAND(p^, 255)) then
  188.                                                                     p^ := thispixel;
  189.                                                             end;     {else}
  190.                                                     end;     {BrightestPoint case}
  191.                                             end;
  192.                                     end;     {for j}
  193.                             end;     {for i}
  194.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  195.                         if CommandPeriod then begin
  196.                                 cancelled := true;
  197.                                 beep;
  198.                                 leave;
  199.                             end;
  200.                     end;     {for k}
  201.             end;     {with}
  202.     end;     {procedure DoOneProjectionX}
  203.  
  204.  
  205.  
  206. {******************************************************************************}
  207. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  208. {*  the y-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  209. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  210. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  211. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  212. {******************************************************************************}
  213.     procedure DoOneProjectionY (nSlices, xcenter, zcenter: integer; projwidth, projheight: LongInt; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  214.         var
  215.             i, j, k, thispixel: integer;
  216.             offset, offsetinit: longint;
  217.             projaddr, opaaddr, brightcueaddr, zbufaddr, cuezbufaddr, countbufaddr, sumbufaddr: longint;
  218.             z, xnew, znew, zmax, zmin, zmaxminuszmintimes100: longint;
  219.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  220.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  221.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  222.             MeanVal, BrightestPt: boolean;
  223.             xsintheta, xcostheta, zsintheta, zcostheta, xsinthetainit, xcosthetainit: longint;
  224.             p, op, bp: ptr;
  225.             zp, qp, cp: IntPtr;
  226.             sp: LongPtr;
  227.             width: integer;
  228.             aLine: LineType;
  229.     begin
  230.         with BoundRect do begin
  231.                 width := right - left;
  232.                 zmax := zcenter + projwidth div 2;
  233.                 zmin := zcenter - projwidth div 2;
  234.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  235.                 c100minusDepthCueInt := 100 - DepthCueInt;
  236.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  237.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  238.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  239.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  240.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  241.                 MeanVal := ProjectionMethod = MeanValue;
  242.                 BrightestPt := ProjectionMethod = BrightestPoint;
  243.                 projaddr := ord4(projptr);
  244.                 opaaddr := ord4(opaptr);
  245.                 brightcueaddr := ord4(brightcueptr);
  246.                 zbufaddr := ord4(zbufptr);
  247.                 cuezbufaddr := ord4(cuezbufptr);
  248.                 countbufaddr := ord4(countbufptr);
  249.                 sumbufaddr := ord4(sumbufptr);
  250.                 xcosthetainit := (left - xcenter - 1) * costheta;
  251.                 xsinthetainit := (left - xcenter - 1) * sintheta;
  252.                 for k := 1 to nSlices do begin
  253.                         SelectSlice(k);
  254.                         z := round((k - 1) * SliceInterval) - zcenter;
  255.                         zcostheta := z * costheta;
  256.                         zsintheta := z * sintheta;
  257.                         offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 - projwidth;
  258.                         for j := top to bottom - 1 do begin
  259.                                 xcostheta := xcosthetainit;
  260.                                 xsintheta := xsinthetainit;
  261.                                 offsetinit := offsetinit + projwidth;
  262.                                 GetLine(left, j, width, aLine);
  263.                                 for i := 0 to width - 1 do begin
  264.                                         thispixel := aLine[i];
  265.                                         xcostheta := xcostheta + costheta;
  266.                                         xsintheta := xsintheta + sintheta;
  267.                                         if (thispixel <= TransparencyUpper) and (thispixel >= TransparencyLower) then begin
  268.                                                 xnew := (xcostheta + zsintheta) div bigpowerof2 + xcenter - left;
  269.                                                 znew := (zcostheta - xsintheta) div bigpowerof2 + zcenter;
  270.                                                 offset := offsetinit + xnew;
  271.                                                 if (offset >= ProjSize) or (offset < 0) then
  272.                                                     offset := 0;
  273.                                                 if OpacityOrNearestPt then begin
  274.                                                         zp := IntPtr(zbufaddr + offset + offset);
  275.                                                         if (znew < zp^) then begin
  276.                                                                 zp^ := znew;
  277.                                                                 if OpacityAndNotNearestPt then begin
  278.                                                                         op := ptr(opaaddr + offset);
  279.                                                                         if (DepthCueSurflessthan100) then
  280.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  281.                                                                         else
  282.                                                                             op^ := thispixel;
  283.                                                                     end
  284.                                                                 else begin
  285.                                                                         p := ptr(projaddr + offset);
  286.                                                                         if DepthCueSurflessthan100 then
  287.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  288.                                                                         else
  289.                                                                             p^ := thispixel;
  290.                                                                     end;
  291.                                                             end;
  292.                                                     end;     {NearestPoint case}
  293.                                                 if MeanVal then begin
  294.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  295.                                                         sp^ := sp^ + thispixel;
  296.                                                         cp := IntPtr(countbufaddr + offset + offset);
  297.                                                         cp^ := cp^ + 1;
  298.                                                     end     {MeanValue case}
  299.                                                 else if BrightestPt then begin
  300.                                                         if (DepthCueIntlessthan100) then begin
  301.                                                                 p := ptr(projaddr + offset);
  302.                                                                 bp := ptr(brightcueaddr + offset);
  303.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  304.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (znew < qp^)) then begin
  305.                                                                         bp^ := thispixel;
  306.                                                                         qp^ := znew;
  307.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100);
  308.                                                                     end;     {then}
  309.                                                             end
  310.                                                         else begin
  311.                                                                 p := ptr(projaddr + offset);
  312.                                                                 if (thispixel < BAND(p^, 255)) then
  313.                                                                     p^ := thispixel;
  314.                                                             end;     {else}
  315.                                                     end;     {BrightestPoint case}
  316.                                             end;
  317.                                     end;     {for j}
  318.                             end;     {for i}
  319.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  320.                         if CommandPeriod then begin
  321.                                 cancelled := true;
  322.                                 beep;
  323.                                 leave;
  324.                             end;
  325.                     end;     {for k}
  326.             end;     {with}
  327.     end;     {procedure DoOneProjectionY}
  328.  
  329.  
  330.  
  331. {******************************************************************************}
  332. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  333. {*  the z-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  334. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  335. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  336. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  337. {******************************************************************************}
  338.     procedure DoOneProjectionZ (nSlices, xcenter, ycenter, zcenter: integer; projwidth, projheight: LongInt; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  339.         var
  340.             i, j, k, thispixel: integer;
  341.             offset, offsetinit: longint;
  342.             projaddr, opaaddr, brightcueaddr, zbufaddr, cuezbufaddr, countbufaddr, sumbufaddr: longint;
  343.             z, xnew, ynew, zmax, zmin, zmaxminuszmintimes100: longint;
  344.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  345.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  346.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  347.             MeanVal, BrightestPt: boolean;
  348.             xsintheta, xcostheta, ysintheta, ycostheta: longint;
  349.             xsinthetainit, xcosthetainit, ysinthetainit, ycosthetainit: longint;
  350.             p, op, bp: ptr;
  351.             zp, qp, cp: IntPtr;
  352.             sp: LongPtr;
  353.             width: integer;
  354.             theLine: LineType;
  355.     begin
  356.         with BoundRect do begin
  357.                 width := right - left;
  358.                 zmax := zcenter + projwidth div 2;
  359.                 zmin := zcenter - projwidth div 2;
  360.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  361.                 c100minusDepthCueInt := 100 - DepthCueInt;
  362.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  363.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  364.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  365.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  366.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  367.                 MeanVal := ProjectionMethod = MeanValue;
  368.                 BrightestPt := ProjectionMethod = BrightestPoint;
  369.                 projaddr := ord4(projptr);
  370.                 opaaddr := ord4(opaptr);
  371.                 brightcueaddr := ord4(brightcueptr);
  372.                 zbufaddr := ord4(zbufptr);
  373.                 cuezbufaddr := ord4(cuezbufptr);
  374.                 countbufaddr := ord4(countbufptr);
  375.                 sumbufaddr := ord4(sumbufptr);
  376.                 xcosthetainit := (left - xcenter - 1) * costheta;
  377.                 xsinthetainit := (left - xcenter - 1) * sintheta;
  378.                 ycosthetainit := (top - ycenter - 1) * costheta;
  379.                 ysinthetainit := (top - ycenter - 1) * sintheta;
  380.                 offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 + left - 1;
  381.                 for k := 1 to nSlices do begin
  382.                         SelectSlice(k);
  383.                         z := round((k - 1) * SliceInterval) - zcenter;
  384.                         ycostheta := ycosthetainit;
  385.                         ysintheta := ysinthetainit;
  386.                         for j := top to bottom - 1 do begin
  387.                                 ycostheta := ycostheta + costheta;
  388.                                 ysintheta := ysintheta + sintheta;
  389.                                 xcostheta := xcosthetainit;
  390.                                 xsintheta := xsinthetainit;
  391.                                 GetLine(left, j, width, theLine);
  392.                                 for i := 0 to width - 1 do begin
  393.                                         thisPixel := theLine[i];
  394.                                         xcostheta := xcostheta + costheta;
  395.                                         xsintheta := xsintheta + sintheta;
  396.                                         if (thispixel <= TransparencyUpper) and (thispixel >= TransparencyLower) then begin
  397.                                                 xnew := (xcostheta - ysintheta) div bigpowerof2 + xcenter - left;
  398.                                                 ynew := (xsintheta + ycostheta) div bigpowerof2 + ycenter - top;
  399.                                                 offset := offsetinit + ynew * projwidth + xnew;
  400.                                                 if (offset >= ProjSize) or (offset < 0) then
  401.                                                     offset := 0;
  402.                                                 if OpacityOrNearestPt then begin
  403.                                                         zp := IntPtr(zbufaddr + offset + offset);
  404.                                                         if (z < zp^) then begin
  405.                                                                 zp^ := z;
  406.                                                                 if OpacityAndNotNearestPt then begin
  407.                                                                         op := ptr(opaaddr + offset);
  408.                                                                         if (DepthCueSurflessthan100) then
  409.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100)
  410.                                                                         else
  411.                                                                             op^ := thispixel;
  412.                                                                     end
  413.                                                                 else begin
  414.                                                                         p := ptr(projaddr + offset);
  415.                                                                         if DepthCueSurflessthan100 then
  416.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100)
  417.                                                                         else
  418.                                                                             p^ := thispixel;
  419.                                                                     end;
  420.                                                             end;
  421.                                                     end;     {NearestPoint case}
  422.                                                 if MeanVal then begin
  423.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  424.                                                         sp^ := sp^ + thispixel;
  425.                                                         cp := IntPtr(countbufaddr + offset + offset);
  426.                                                         cp^ := cp^ + 1;
  427.                                                     end     {MeanValue case}
  428.                                                 else if BrightestPt then begin
  429.                                                         if (DepthCueIntlessthan100) then begin
  430.                                                                 p := ptr(projaddr + offset);
  431.                                                                 bp := ptr(brightcueaddr + offset);
  432.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  433.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (z < qp^)) then begin
  434.                                                                         bp^ := thispixel;
  435.                                                                         qp^ := z;
  436.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100);
  437.                                                                     end;     {then}
  438.                                                             end
  439.                                                         else begin
  440.                                                                 p := ptr(projaddr + offset);
  441.                                                                 if (thispixel < BAND(p^, 255)) then
  442.                                                                     p^ := thispixel;
  443.                                                             end;     {else}
  444.                                                     end;     {BrightestPoint case}
  445.                                             end;
  446.                                     end;     {for j}
  447.                             end;     {for i}
  448.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  449.                         if CommandPeriod then begin
  450.                                 cancelled := true;
  451.                                 beep;
  452.                                 leave;
  453.                             end;
  454.                     end;     {for k}
  455.             end;     {with}
  456.     end;     {procedure DoOneProjectionZ}
  457.  
  458.  
  459.  
  460. {******************************************************************************}
  461. {*     This code initializes buffers by filling them with uniform values. The *}
  462. {*     The buffer can be filled with one, two or four byte values.            *}
  463. {******************************************************************************}
  464.     procedure InitializeBuffer (p: ptr; size: longint; value, step: integer);
  465.     type
  466.         IntPtrType=^integer;
  467.         LongPtrType=^LongInt;
  468.     var
  469.         i, Lstep: longint;
  470.         IntPtr:IntPtrTYpe;
  471.         LongPtr:LongPtrType;
  472.     begin
  473.         Lstep:=step;
  474.         case step of
  475.             1: for i := 1 to size do begin
  476.                     p^ := value;
  477.                     p := Ptr(ord4(p) + Lstep);
  478.                 end;
  479.             2: begin
  480.                     IntPtr:=IntPtrType(p);
  481.                     for i := 1 to size do begin
  482.                         IntPtr^ := value;
  483.                         IntPtr := IntPtrType(ord4(IntPtr) + Lstep);
  484.                     end;
  485.                 end;
  486.             4: begin
  487.                     LongPtr:=LongPtrType(p);
  488.                     for i := 1 to size do begin
  489.                         LongPtr^ := value;
  490.                         LongPtr := LongPtrType(ord4(LongPtr) + Lstep);
  491.                     end;
  492.                 end;
  493.         end;
  494.     end;
  495.  
  496.  
  497.  
  498. {******************************************************************************}
  499. {*     This procedure creates a sequence of projections of a rotating volume (stack of slices) onto a plane using   *}
  500. {*  nearest-point (surface), brightest-point, or mean-value projection or a weighted combination of nearest- *}
  501. {*  point projection with either of the other two methods (partial opacity).  The user may choose to rotate the   *}
  502. {*  volume about any of the three orthogonal axes (x,y, or z), make portions of the volume transparent, or add  *}
  503. {*  a greater degree of visual realism by employing depth cues.                                                                               *}
  504. {******************************************************************************}
  505. procedure DoProjection;
  506.     var
  507.         tport: Grafptr;
  508.         nSlices: integer;                                      {number of slices in volume}
  509.         projwidth, projheight: LongInt;              {dimensions of projection image}
  510.         xcenter, ycenter, zcenter: integer;         {coordinates of center of volume of rotation}
  511.         theta: integer;                                          {current angle of rotation in degrees}
  512.         thetarad: extended;                                          {current angle of rotation in radians}
  513.         sintheta, costheta: longint;                      {sine and cosine of current angle}
  514.         xsinthetainit, xcosthetainit: longint;      {precomputed products to avoid mult in loops}
  515.         offset, MemoryRequired: longint;
  516.         p, op, bp, projptr, opaptr, brightcueptr: ptr;
  517.         zp, zbufptr, qp, cuezbufptr, countbufptr, cp: IntPtr;
  518.         sp, sumbufptr: LongPtr;
  519.         curval, prevval, nextval, aboveval, belowval: integer;
  520.         ignore: integer;                                        {irrelevant return value from a function}
  521.         ticksinit, tickstogo, TicksForOneProjection: longint;
  522.         str, TimeStr, seconds: str255;
  523.         SaveProjectionsTemp, AutoSelectAll, AllocatingBuffers: boolean;
  524.         n, nProjections, angle: integer;
  525.         SourceInfo, DestInfo: InfoPtr;
  526.         width, height: LongInt;
  527.  
  528.     procedure Abort;
  529.     begin
  530.         DisposeProjectionPtrs(projptr, opaptr, brightcueptr, zbufptr, countbufptr, cuezbufptr, sumbufptr);
  531.         if AllocatingBuffers and (MaxBlock > 20000) then
  532.             PutError('Insufficient Memory.');
  533.         AbortMacro;
  534.         {exit(DoProjection);} {ppc-bug}
  535.     end;
  536.  
  537. begin
  538.     ShowWatch;
  539.     AutoSelectAll := not Info^.RoiShowing;
  540.     if AutoSelectAll then
  541.         SelectAll(false);
  542.     if NotInBounds then
  543.         exit(DoProjection);
  544.     cancelled := false;
  545.     SourceInfo := Info;
  546.     GetPort(tPort);
  547.     with Info^ do begin
  548.             SetPort(GrafPtr(osPort));
  549.             BoundRect := Roirect;
  550.         end;
  551.     if (AngleInc = 0) and (TotalAngle <> 0) then
  552.         AngleInc := 5;
  553.     angle := 0;
  554.     nProjections := 0;
  555.     if AngleInc = 0 then
  556.         nProjections := 1
  557.     else
  558.         while angle <= TotalAngle do begin
  559.                 nProjections := nProjections + 1;
  560.                 angle := angle + AngleInc;
  561.             end;
  562.     if angle > 360 then
  563.         nProjections := nProjections - 1;
  564.     if nProjections <= 0 then
  565.         nProjections := 1;
  566.     nSlices := Info^.StackInfo^.nSlices;         {get number of slices in volume}
  567.     SliceInterval := info^.StackInfo^.SliceSpacing;
  568.     with BoundRect do begin
  569.             width := right - left;
  570.             height := bottom - top;
  571.             xcenter := (left + right) div 2;          {find center of volume of rotation}
  572.             ycenter := (top + bottom) div 2;
  573.             zcenter := round(nSlices * SliceInterval / 2.0);
  574.             if MinProjSize and (AxisOfRotation <> ZAxis) then begin
  575.                     case AxisOfRotation of                    {find dimensions of projection image}
  576.                         XAxis:  begin
  577.                                 projheight := round(sqrt(sqr(nSlices * SliceInterval) + height * height));
  578.                                 projwidth := right - left;
  579.                             end;     {XAxis}
  580.                         YAxis:  begin
  581.                                 projwidth := round(sqrt(sqr(nSlices * SliceInterval) + ord4(right - left) * (right - left)));
  582.                                 projheight := bottom - top;
  583.                             end;     {YAxis}
  584.                     end;     {case}
  585.                 end     {then}
  586.             else begin
  587.                     projwidth := round(sqrt(sqr(nSlices * SliceInterval) + width * width));
  588.                     projheight := round(sqrt(sqr(nSlices * SliceInterval) + height * height));
  589.                 end;     {else make all windows the same size regardless of rotation axis}
  590.         end;     {with BoundRect}
  591.     if odd(projwidth) then
  592.         projwidth := projwidth + 1;
  593.     projptr := nil;
  594.     zbufptr := nil;
  595.     opaptr := nil;
  596.     brightcueptr := nil;
  597.     cuezbufptr := nil;
  598.     sumbufptr := nil;
  599.     countbufptr := nil;
  600.     AllocatingBuffers := true;
  601.     projsize := projwidth * projheight;
  602.     projptr := NewPtr(projsize);
  603.     if projptr = nil then
  604.         begin Abort; exit(DoProjection) end;
  605.  
  606.     if (ProjectionMethod = NearestPoint) or (Opacity > 0) then begin    {get other required buffers}
  607.             zbufptr := IntPtr(NewPtr(projsize * 2));
  608.             if zbufptr = nil then
  609.                 begin Abort; exit(DoProjection) end;
  610.         end;
  611.     if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  612.             opaptr := NewPtr(projsize);
  613.             if opaptr = nil then
  614.                 begin Abort; exit(DoProjection) end;
  615.         end;
  616.     if (ProjectionMethod = BrightestPoint) and (DepthCueInt < 100) then begin
  617.             brightcueptr := NewPtr(projsize);
  618.             cuezbufptr := IntPtr(NewPtr(projsize * 2));
  619.             if (brightcueptr = nil) or (cuezbufptr = nil) then
  620.                 begin Abort; exit(DoProjection) end;
  621.         end;
  622.     if (ProjectionMethod = MeanValue) then begin
  623.             sumbufptr := LongPtr(NewPtr(projsize * 4));
  624.             countbufptr := IntPtr(NewPtr(projsize * 2));
  625.             if (sumbufptr = nil) or (countbufptr = nil) then
  626.                 begin Abort; exit(DoProjection) end;
  627.         end;
  628.     AllocatingBuffers := false;
  629.     SaveProjectionsTemp := FALSE;              {check whether we have enough memory to open}
  630.     MemoryRequired := nProjections * projsize + SizeOf(PicInfo) + MinFree;
  631.     if (MemoryRequired > FreeMem) and not (SaveProjections) then begin
  632.             str := 'Insufficient memory to create entire stack of projections.  Projection images will be saved to disk.';
  633.             if (PutMessageWithCancel(str) = cancel) then
  634.                 begin Abort; exit(DoProjection) end;
  635.             SaveProjections := TRUE;
  636.             SaveProjectionsTemp := TRUE;
  637.         end;
  638.     if (SaveProjections) then begin           {prepare to save projections as created if desired}
  639.             SaveAsWhat := AsTiff;
  640.             SaveAllState := SaveAllStage1;
  641.         end;
  642.     TimeStr := '?';
  643.     theta := InitAngle;                                     {begin rotation with user-specified angle}
  644.     ticksinit := TickCount;
  645.     for n := 1 to nProjections do begin
  646.             if (SaveProjections) or (n = 1) then begin    {open new window or stack slice}
  647.                     if SaveProjections then
  648.                         case AxisOfRotation of
  649.                             XAxis: 
  650.                                 str := StringOf('Projection X ', theta:3);
  651.                             YAxis: 
  652.                                 str := StringOf('Projection Y ', theta:3);
  653.                             ZAxis: 
  654.                                 str := StringOf('Projection Z ', theta:3);
  655.                         end
  656.                     else
  657.                         str := 'Projections';
  658.                     if not NewPicWindow(str, projwidth, projheight) then
  659.                         begin Abort; exit(DoProjection) end;
  660.                 end
  661.             else if not (AddSlice(false)) then
  662.                 begin Abort; exit(DoProjection) end;
  663.             str := concat('Projecting: ', long2str(n), '/', long2str(nProjections), ' (', long2str(Theta), '°', ', ', TimeStr, ')');
  664.             ShowMeter;
  665.             UpdateMeter(0, str);
  666.             thetarad := theta * pi / 180.0;
  667.             costheta := round(bigpowerof2 * cos(thetarad));
  668.             sintheta := round(bigpowerof2 * sin(thetarad));
  669.             p := projptr;                                          {initialize required projection buffers}
  670.             InitializeBuffer(p, projsize, 255, 1);
  671.             if (ProjectionMethod = NearestPoint) or (Opacity > 0) then begin
  672.                     zp := zbufptr;
  673.                     InitializeBuffer(Ptr(zp), projsize, 32767, 2);
  674.                 end;     {then}
  675.             if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  676.                     op := opaptr;
  677.                     InitializeBuffer(op, projsize, 255, 1);
  678.                 end;     {then}
  679.             if (ProjectionMethod = MeanValue) then begin
  680.                     sp := sumbufptr;
  681.                     cp := countbufptr;
  682.                     InitializeBuffer(Ptr(sp), projsize, 0, 4);
  683.                     InitializeBuffer(Ptr(cp), projsize, 0, 2);
  684.                 end;
  685.             if (ProjectionMethod = BrightestPoint) and (DepthCueInt < 100) then begin
  686.                     bp := brightcueptr;
  687.                     InitializeBuffer(bp, projsize, 255, 1);
  688.                     qp := cuezbufptr;
  689.                     InitializeBuffer(Ptr(qp), projsize, 255, 2);
  690.                 end;     {then}
  691.             UpdateMeter(10, str);
  692.             DestInfo := Info;
  693.             Info := SourceInfo;
  694.             case AxisOfRotation of
  695.                 XAxis: 
  696.                     DoOneProjectionX(nSlices, ycenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  697.                 YAxis: 
  698.                     DoOneProjectionY(nSlices, xcenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  699.                 ZAxis: 
  700.                     DoOneProjectionZ(nSlices, xcenter, ycenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  701.             end;
  702.             Info := DestInfo;
  703.             if n = 1 then
  704.                 TicksForOneProjection := TickCount - TicksInit;
  705.             TicksToGo := (nProjections - n) * TicksForOneProjection;
  706.             NumToString((TicksToGo div 60) mod 60, seconds);
  707.             if length(seconds) = 1 then
  708.                 seconds := concat('0', seconds);
  709.             timestr := concat(long2str(TicksToGo div 3600), ':', seconds);
  710.             if (ProjectionMethod = MeanValue) then begin
  711.                     p := projptr;                                    {calculate the mean-value image from returned info}
  712.                     sp := sumbufptr;
  713.                     cp := countbufptr;
  714.                     for offset := 0 to projsize - 1 do begin
  715.                             if (cp^ > 0) then
  716.                                 p^ := sp^ div cp^;
  717.                             p := ptr(ord4(p) + 1);
  718.                             sp := LongPtr(ord4(sp) + 4);
  719.                             cp := IntPtr(ord4(cp) + 2);
  720.                         end;     {for}
  721.                 end;     {then}
  722.             if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  723.                     p := projptr;                                    {calculate surface proj component (opacity on)}
  724.                     op := opaptr;                                     {and combine with another proj component}
  725.                     for offset := 0 to projsize - 1 do begin
  726.                             p^ := (Opacity * BAND(op^, 255) + (100 - Opacity) * BAND(p^, 255)) div 100;
  727.                             p := ptr(ord4(p) + 1);
  728.                             op := ptr(ord4(op) + 1);
  729.                         end;     {for}
  730.                 end;     {then}
  731.             if (AxisOfRotation = ZAxis) then begin  {interpolate for z-axis rotation}
  732.                     p := ptr(ord4(projptr) + projwidth);
  733.                     for offset := projwidth to projsize - 1 - projwidth do begin
  734.                             curval := BAND(p^, 255);
  735.                             prevval := BAND(ptr(ord4(p) - 1)^, 255);
  736.                             nextval := BAND(ptr(ord4(p) + 1)^, 255);
  737.                             aboveval := BAND(ptr(ord4(p) - projwidth)^, 255);
  738.                             belowval := BAND(ptr(ord4(p) + projwidth)^, 255);
  739.                             if (curval = 255) and (prevval <> 255) and (nextval <> 255) and (aboveval <> 255) and (belowval <> 255) then
  740.                                 p^ := (prevval + nextval + aboveval + belowval) div 4;
  741.                             p := ptr(ord4(p) + 1);
  742.                         end;
  743.                 end;
  744.             if (SaveProjections) or (n = 1) then
  745.                 BlockMove(projptr, Info^.PicBaseAddr, projsize)         {whole ROI write to projection image}
  746.             else
  747.                 BlockMove(projptr, Info^.StackInfo^.PicBaseH[n]^, projsize);
  748.             UpdateMeter(-1, '');        {dispose of meter}
  749.             if cancelled then begin
  750.                     if n > 1 then
  751.                         DeleteSlice;
  752.                     leave;
  753.                 end;
  754.             if (SaveProjections) then begin
  755.                     SaveAs('', 0);                                    {just save and put away current image after creating it}
  756.                     ignore := CloseAWindow(info^.wptr);
  757.                 end
  758.             else if n = 1 then begin  {create new stack for first projection if not saving projections}
  759.                     if not MakeStackFromWindow then
  760.                         begin Abort; exit(DoProjection) end
  761.                 end;
  762.             theta := (theta + AngleInc) mod 360;
  763.             UpdatePicWindow;
  764.         end;     {for}
  765.     SaveAllState := NoSaveAll;
  766.     if SaveProjectionsTemp then                 {turn this back off if we turned it on due to lack of memory}
  767.         SaveProjections := FALSE;
  768.     DisposeProjectionPtrs(projptr, opaptr, brightcueptr, zbufptr, countbufptr, cuezbufptr, sumbufptr);
  769.     SetPort(tPort);
  770.     DestInfo := info;
  771.     info := SourceInfo;
  772.     SelectSlice(info^.StackInfo^.CurrentSlice);
  773.     if AutoSelectAll then
  774.         KillRoi;
  775.     info := DestInfo;
  776. end;     {procedure DoProjection}
  777.  
  778.  
  779.  
  780. {******************************************************************************}
  781. {*     This procedure allows the user to set parameters for projection in a large dialog box.                                  *}
  782. {******************************************************************************}
  783. function ShowProjectDialogBox: boolean;
  784.     const
  785.         ProjectOptionsID = 128;
  786.         SliceIntervalID = 3;
  787.         InitAngleID = 4;
  788.         TotalAngleID = 5;
  789.         AngleIncID = 6;
  790.         TransparencyLowerID = 7;
  791.         TransparencyUpperID = 8;
  792.         OpacityID = 9;
  793.         DepthCueSurfID = 10;
  794.         DepthCueIntID = 11;
  795.         RotationAboutXID = 12;
  796.         RotationAboutYID = 13;
  797.         RotationAboutZID = 14;
  798.         SaveProjectionsID = 15;
  799.         MinProjSizeID = 16;
  800.         NearestID = 28;
  801.         BrightestID = 29;
  802.         MeanID = 30;
  803.     var
  804.         mylog: Dialogptr;                                           {pointer to dialog box}
  805.         i, item, alldone: integer;
  806.         SaveInitAngle, SaveTotalAngle, SaveAngleInc: integer;
  807.         SaveOpacity: integer;
  808.         SaveAxisOfRotation: AxisType;
  809.         SaveSaveProjections, SaveCloseSlices, SaveMinProjSize: Boolean;
  810.         SaveLower, SaveUpper: integer;
  811.         PercentSurf, PercentInt: integer;
  812.         interval: extended;
  813. begin
  814.     InitCursor;
  815.     Interval := info^.StackInfo^.SliceSpacing;
  816.     if Interval <= 0.0 then
  817.         Interval := 1.0;
  818.     SaveInitAngle := InitAngle;
  819.     SaveTotalAngle := TotalAngle;
  820.     SaveAngleInc := AngleInc;
  821.     SaveOpacity := Opacity;
  822.     SaveAxisOfRotation := AxisOfRotation;
  823.     SaveSaveProjections := SaveProjections;
  824.     SaveMinProjSize := MinProjSize;
  825.     SaveLower := TransparencyLower;
  826.     SaveUpper := TransparencyUpper;
  827.     PercentSurf := 100 - DepthCueSurf;
  828.     PercentInt := 100 - DepthCueInt;
  829.     if DensitySlicing then
  830.         with info^ do begin
  831.                 TransparencyLower := SliceStart;
  832.                 TransparencyUpper := SliceEnd;
  833.             end;
  834.     mylog := GetNewDialog(ProjectOptionsID, nil, pointer(-1));
  835.     SetDReal(MyLog, SliceIntervalID, Interval, 1);
  836.     SelectdialogItemText(MyLog, SliceIntervalID, 0, 32767);
  837.     SetDNum(MyLog, InitAngleID, InitAngle);
  838.     SetDNum(MyLog, TotalAngleID, TotalAngle);
  839.     SetDNum(MyLog, AngleIncID, AngleInc);
  840.     SetDNum(MyLog, TransparencyLowerID, TransparencyLower);
  841.     SetDNum(MyLog, TransparencyUpperID, TransparencyUpper);
  842.     SetDNum(MyLog, OpacityID, Opacity);
  843.     SetDNum(MyLog, DepthCueSurfID, PercentSurf);
  844.     SetDNum(MyLog, DepthCueIntID, PercentInt);
  845.     OutlineButton(MyLog, ok, 16);
  846.     SetDlogItem(MyLog, RotationAboutXID, ord(AxisOfRotation = XAxis));
  847.     SetDlogItem(MyLog, RotationAboutYID, ord(AxisOfRotation = YAxis));
  848.     SetDlogItem(MyLog, RotationAboutZID, ord(AxisOfRotation = ZAxis));
  849.     SetDlogItem(MyLog, NearestID, ord(ProjectionMethod = NearestPoint));
  850.     SetDlogItem(MyLog, BrightestID, ord(ProjectionMethod = BrightestPoint));
  851.     SetDlogItem(MyLog, MeanID, ord(ProjectionMethod = MeanValue));
  852.     SetDlogItem(MyLog, SaveProjectionsID, ord(SaveProjections));
  853.     SetDlogItem(MyLog, MinProjSizeID, ord(MinProjSize));
  854.     alldone := 0;
  855.     repeat  {if we don't do it this way, ModalDialog throws us into code checking after each keystroke}
  856.         repeat   {meaning you can't type in a 2 digit number}
  857.             ModalDialog(nil, item);
  858.             if item = SaveProjectionsID then begin
  859.                     SaveProjections := not SaveProjections;
  860.                     SetDlogItem(MyLog, SaveProjectionsID, ord(SaveProjections));
  861.                 end;
  862.             if item = MinProjSizeID then begin
  863.                     MinProjSize := not MinProjSize;
  864.                     SetDlogItem(MyLog, MinProjSizeID, ord(MinProjSize));
  865.                 end;
  866.             if (item = RotationAboutXID) or (item = RotationAboutYID) or (item = RotationAboutZID) then begin
  867.                     case item of
  868.                         RotationAboutXID: 
  869.                             AxisOfRotation := XAxis;
  870.                         RotationAboutYID: 
  871.                             AxisOfRotation := YAxis;
  872.                         RotationAboutZID: 
  873.                             AxisOfRotation := ZAxis;
  874.                     end;     {case}
  875.                     SetDlogItem(MyLog, RotationAboutXID, ord(AxisOfRotation = XAxis));
  876.                     SetDlogItem(MyLog, RotationAboutYID, ord(AxisOfRotation = YAxis));
  877.                     SetDlogItem(MyLog, RotationAboutZID, ord(AxisOfRotation = ZAxis));
  878.                 end;
  879.             if (item >= nearestID) and (item <= MeanID) then begin
  880.                     case item of
  881.                         NearestID: 
  882.                             ProjectionMethod := NearestPoint;
  883.                         BrightestID: 
  884.                             ProjectionMethod := BrightestPoint;
  885.                         MeanID: 
  886.                             ProjectionMethod := MeanValue;
  887.                     end;
  888.                     SetDlogItem(MyLog, NearestID, ord(projectionMethod = NearestPoint));
  889.                     SetDlogItem(MyLog, BrightestID, ord(projectionMethod = BrightestPoint));
  890.                     SetDlogItem(MyLog, MeanID, ord(projectionMethod = MeanValue));
  891.                 end;
  892.         until (item = ok) or (item = cancel);
  893.         alldone := 1;
  894.         if (item = ok) then begin  {check all the values that could have been entered, don't know which were changed}
  895.                 Interval := GetDReal(MyLog, SliceIntervalID);
  896.                 if (Interval <= 0.0) or (Interval > 1023.0) then begin
  897.                         Interval := info^.StackInfo^.SliceSpacing;
  898.                         SetDReal(MyLog, SliceIntervalID, Interval, 1);
  899.                         beep;
  900.                         alldone := 0;
  901.                     end;  {if Interval}
  902.                 InitAngle := GetDNum(MyLog, InitAngleID);
  903.                 if (InitAngle < 0) or (InitAngle > 360) then begin
  904.                         InitAngle := SaveInitAngle;
  905.                         SetDNum(MyLog, InitAngleID, InitAngle);
  906.                         beep;
  907.                         alldone := 0;
  908.                     end;  {if InitAngle}
  909.                 TotalAngle := GetDNum(MyLog, TotalAngleID);
  910.                 if (TotalAngle < 0) or (TotalAngle > 360) then begin
  911.                         TotalAngle := SaveTotalAngle;
  912.                         SetDNum(MyLog, TotalAngleID, TotalAngle);
  913.                         beep;
  914.                         alldone := 0;
  915.                     end;  {if TotalAngle}
  916.                 AngleInc := GetDNum(MyLog, AngleIncID);
  917.                 if (AngleInc < 0) or (AngleInc > 360) then begin
  918.                         AngleInc := SaveAngleInc;
  919.                         SetDNum(MyLog, AngleIncID, AngleInc);
  920.                         beep;
  921.                         alldone := 0;
  922.                     end;  {if AngleInc}
  923.                 TransparencyLower := GetDNum(MyLog, TransparencyLowerID);
  924.                 if (TransparencyLower < 0) or (TransparencyLower > 255) then begin
  925.                         TransparencyLower := SaveLower;
  926.                         SetDNum(MyLog, TransparencyLowerID, TransparencyLower);
  927.                         beep;
  928.                         alldone := 0;
  929.                     end;  {if TransparencyLower}
  930.                 TransparencyUpper := GetDNum(MyLog, TransparencyUpperID);
  931.                 if (TransparencyUpper < 0) or (TransparencyUpper > 255) then begin
  932.                         TransparencyUpper := SaveUpper;
  933.                         SetDNum(MyLog, TransparencyUpperID, TransparencyUpper);
  934.                         beep;
  935.                         alldone := 0;
  936.                     end;  {if TransparencyUpper}
  937.                 Opacity := GetDNum(MyLog, OpacityID);
  938.                 if (Opacity < 0) or (Opacity > 100) then begin
  939.                         Opacity := SaveOpacity;
  940.                         SetDNum(MyLog, OpacityID, Opacity);
  941.                         beep;
  942.                         alldone := 0;
  943.                     end;  {if Opacity}
  944.                 PercentSurf := GetDNum(MyLog, DepthCueSurfID);
  945.                 if (PercentSurf < 0) or (PercentSurf > 100) then begin
  946.                         PercentSurf := 100 - DepthCueSurf;
  947.                         SetDNum(MyLog, DepthCueSurfID, PercentSurf);
  948.                         beep;
  949.                         alldone := 0;
  950.                     end;  {if DepthCueSurf}
  951.                 PercentInt := GetDNum(MyLog, DepthCueIntID);
  952.                 if (PercentInt < 0) or (PercentInt > 100) then begin
  953.                         PercentInt := 100 - DepthCueInt;
  954.                         SetDNum(MyLog, DepthCueIntID, PercentInt);
  955.                         beep;
  956.                         alldone := 0;
  957.                     end;  {if DepthCueInt}
  958.                 info^.StackInfo^.SliceSpacing := Interval;
  959.             end;
  960.     until (alldone = 1);
  961.     DisposeDialog(mylog);
  962.     if item = cancel then begin                       {if Cancel, keep the saved values}
  963.             InitAngle := SaveInitAngle;
  964.             TotalAngle := SaveTotalAngle;
  965.             AngleInc := SaveAngleInc;
  966.             Opacity := SaveOpacity;
  967.             AxisOfRotation := SaveAxisOfRotation;
  968.             SaveProjections := SaveSaveProjections;
  969.             MinProjSize := SaveMinProjSize;
  970.             TransparencyLower := SaveLower;
  971.             TransparencyUpper := SaveUpper;
  972.             ShowProjectDialogBox := false;
  973.         end
  974.     else begin
  975.             DepthCueSurf := 100 - PercentSurf;
  976.             DepthCueInt := 100 - PercentInt;
  977.             ShowProjectDialogBox := true;
  978.         end;
  979. end;
  980.  
  981.  
  982. procedure Project;
  983. begin
  984.     if ShowProjectDialogBox then
  985.         DoProjection;
  986. end;
  987.  
  988.  
  989. end.